
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <fcntl.h>
#include <unistd.h>

#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>

#include <event.h>

#include "config.h"

#include "connection.h"
#include "tunable.h"

struct listen_data
{
	struct event event;
	int connId;
};

void listen_event( int listenSocket, short status, void * listenEvent_v );

int main( void )
{
	int listeningSocket;
	int socketAddr_len;
	struct sockaddr_un socketAddr;
	//struct event listenEvents;
	struct listen_data data;
	
	/* Must disable SIGPIPE, certain webservers are very quick to close connections and this can
	 *  interrupt the send system call.  Application receives a SIGPIPE and is unceremoniously
	 *  terminated.
	 * We'd prefer to deal with this "problem" ourselves, if that's alright
	 */
	signal( SIGPIPE, SIG_IGN );
	
	listeningSocket = socket( PF_UNIX, SOCK_STREAM, 0 );
	if( listeningSocket < 0 )
	{
		printf( "Cannot create a UNIX socket to listen on!\n" );
		return 1;
	}
	
	fcntl( listeningSocket, F_SETFL, O_NONBLOCK ); 
	
	socketAddr.sun_family = AF_UNIX;
	strcpy( socketAddr.sun_path, SOCKET_PATH );
	
	socketAddr_len = strlen( socketAddr.sun_path ) + 1 + sizeof( socketAddr.sun_family );

	// TODO: shouldn't just blindly unlink socket, should try and connect to it to prevent double-invocation
	if( unlink( socketAddr.sun_path ) < 0 )
	{
		printf( "Socket exists and couldn't be removed\n" );
		//return 1;
	}
	
	if( bind(listeningSocket, (struct sockaddr *) &socketAddr, socketAddr_len ) < 0 )
	{
		printf( "Cannot bind socket (%i)\n", errno );
		return 1;
	}
	
	listen( listeningSocket, PROXY_LISTEN_BACKLOG );
	
	// TODO: Dodgy!  Make socket R/W to make testing easier!
	chmod( socketAddr.sun_path, 0777 );
	
	event_init();
	
	data.connId = 0;
	event_set( &data.event, listeningSocket, EV_READ, listen_event, &data );
	
	event_add( &data.event, NULL );
	
	event_dispatch();
	
	return 0;
}


void listen_event( int listenSocket, short status, void * listenEvent_v )
{
	struct listen_data * data = (struct listen_data *) listenEvent_v;
	
	int newSocket;
	
	while( (newSocket = accept( listenSocket, NULL, NULL ) ) >= 0 )
	{
		data->connId ++;
		printf( "Got new connection (%i)\n", data->connId );
		
		connection_accept( newSocket, data->connId );
	} 
	
	event_add( &data->event, NULL );
}


